package battle.gameplay;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.ByteBuffer;
import java.util.Scanner;

import jme3tools.converters.ImageToAwt;

import com.jme3.asset.AssetManager;
import com.jme3.bounding.BoundingBox;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.control.PhysicsGhostControl;
import com.jme3.bullet.nodes.PhysicsGhostNode;
import com.jme3.material.Material;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.texture.Image;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.MagFilter;
import com.jme3.texture.Texture.WrapMode;
import com.jme3.texture.Texture2D;

public class GameScene{
	
	private Node scene = new Node("scene");
	private BulletAppState bulletState;
	public int width, height;
	public int map[][];
	
	public GameScene(BulletAppState bulletState){
		this.bulletState = bulletState;
	}
	
	public Vector3f[] loadMap(String gameRef){
		try{
			Scanner in = new Scanner(new File(gameRef));
			width = in.nextInt();
			height = in.nextInt();
			map = new int[width][height];
			char line[];
			int points = 0;
			Vector3f checkPoints[] = new Vector3f[in.nextInt()];
			in.nextLine();
			for (int i = 0; i < height; ++i){
				line = in.nextLine().toCharArray();
				for (int e = 0; e < width; ++e){
					if (line[e] == '*' || line[e] == 'd' || line[e] == 'l' || line[e] == 'u' || line[e] == 'r')
						map[i][e] = 1;
					if (line[e] == 'o')
						map[i][e] = 2;
					else if (line[e] == '#')
						map[i][e] = 3;
					else if (line[e] == 's' || line[e] == 'd')
						checkPoints[points++] = new Vector3f(e, i, Direction.aSouth);
					else if (line[e] == 'e' || line[e] == 'r')
						checkPoints[points++] = new Vector3f(e, i, Direction.aEast);
					else if (line[e] == 'n' || line[e] == 'u')
						checkPoints[points++] = new Vector3f(e, i, Direction.aNorth);
					else if (line[e] == 'w' || line[e] == 'l')
						checkPoints[points++] = new Vector3f(e, i, Direction.aWest);
					else if (line[e] != '.' && line[e] != '*'){
						System.err.println("Error. Not correct input map file.");
						System.exit(1);
					}
					
				}
			}
			in.close();
			return checkPoints;
		}
		catch (Exception exception){
			exception.printStackTrace();
			System.exit(1);
			return null;
		}
	}
	
	public void createScene(AssetManager assetManager){
		BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
		Graphics2D graphic = img.createGraphics();
		graphic.setColor(Color.BLACK);
		
		Material matBeton = new Material(assetManager, "materials/SimpleTextured.j3md");
		matBeton.setTexture("m_ColorMap", assetManager.loadTexture("textures/beton.png"));
		Material matBrick = new Material(assetManager, "materials/SimpleTextured.j3md");
		matBrick.setTexture("m_ColorMap", assetManager.loadTexture("textures/brick.png"));
		
		Spatial betonModel = assetManager.loadModel("models/beton.mesh.xml");
		betonModel.setMaterial(matBeton);
		Spatial brickModel = assetManager.loadModel("models/brick.mesh.xml");
		brickModel.setMaterial(matBrick);
		
		BoxCollisionShape shape = new BoxCollisionShape(new Vector3f(1, 2.5f, 1));
		
		for (int i = 0; i < height; ++i){
			for (int e = 0; e < width; ++e){
				if (map[i][e] != 0){
					graphic.fillRect(i, e, 1, 1);
				}
				if (map[i][e] == 2){
					graphic.fillRect(i, e, 1, 1);
					Spatial brickClone = brickModel.clone();
					appendModel(brickClone, new Point(e, i), shape);
				}
				else if (map[i][e] == 3){
					Spatial betonClone = betonModel.clone();
					appendModel(betonClone, new Point(e, i), shape);
					map[i][e] = 3;
				}
			}
		}
		
		ByteBuffer buff = ByteBuffer.allocateDirect(30000);
		ImageToAwt.convert(img, Image.Format.RGBA8, buff);
		Image image = new Image(Image.Format.RGBA8, width, height, buff);
		
		Geometry ground = new Geometry("ground", new Box(Vector3f.ZERO, new Vector3f(0.1f, width + 20, height + 20)));
		Material mat = new Material(assetManager, "materials/AlphaMapShader.j3md");
		Texture grass = assetManager.loadTexture("textures/grass.jpg");
		grass.setWrap(WrapMode.Repeat);
		mat.setTexture("m_Grass", grass);
		Texture dirt = assetManager.loadTexture("textures/dirt.jpg");
		dirt.setWrap(WrapMode.Repeat);
		mat.setTexture("m_Dirt", dirt);
		Texture alpha = new Texture2D(image);
		alpha.setMagFilter(MagFilter.Nearest);
		alpha.setWrap(WrapMode.BorderClamp);
		mat.setTexture("m_AlphaMap", alpha);
		mat.setFloat("m_ScaleWidth", width);
		mat.setFloat("m_ScaleHeight", height);
		ground.setMaterial(mat);
		ground.setShadowMode(ShadowMode.Receive);
		
		scene.attachChild(ground.rotate(0, 0, -FastMath.HALF_PI).move(-10, 0, -10));
		scene.setModelBound(new BoundingBox());
		scene.updateModelBound();
	}
	
	private void appendModel(Spatial model, Point point, BoxCollisionShape modelShape){
		PhysicsGhostNode modelNode = new PhysicsGhostNode(model, modelShape);
		modelNode.move(point.x + 0.5f, 0, point.y + 0.5f).scale(0.5f);
		modelNode.setShadowMode(ShadowMode.CastAndReceive);
		modelNode.setCollisionGroup(PhysicsGhostControl.COLLISION_GROUP_02);
		modelNode.setName(model.getName() + "_" + point.y + "_" + point.x);
		modelNode.setModelBound(new BoundingBox());
		modelNode.updateModelBound();
		bulletState.getPhysicsSpace().add(modelNode);
		scene.attachChild(modelNode);
	}
	
	public void removeModel(int i, int e){
		Spatial model = scene.getChild("brick-ogremesh_" + i + "_" + e);
		map[i][e] = 1;
		if (model != null){
			model.removeFromParent();
			bulletState.getPhysicsSpace().remove(model);
		}
	}
	
	public void sceneHit(Node model, int dir){
		String modelName = new String(model.getName());
		if (modelName.startsWith("brick-ogremesh")){
			int i = modelName.indexOf("_");
			int e = modelName.lastIndexOf("_");
			i = Integer.parseInt(modelName.substring(i + 1, e));
			e = Integer.parseInt(modelName.substring(e + 1));
			switch (dir){
				case 0:
					System.out.println("here");
					if (map[i - 1][e + 1] < 2)
						removeModel(i, e + 1);
					if (map[i - 1][e - 1] < 2)
						removeModel(i, e - 1);
					break;
				case 1:
					if (map[i + 1][e - 1] < 2)
						removeModel(i + 1, e);
					if (map[i - 1][e - 1] < 2)
						removeModel(i - 1, e);
					break;
				case 2:
					if (map[i + 1][e + 1] < 2)
						removeModel(i, e + 1);
					if (map[i + 1][e - 1] < 2)
						removeModel(i, e - 1);
				case 3:
					if (map[i + 1][e + 1] < 2)
						removeModel(i + 1, e);
					if (map[i - 1][e + 1] < 2)
						removeModel(i - 1, e);
					break;
			}
			bulletState.getPhysicsSpace().remove(model);
			model.removeFromParent();
			map[i][e] = 1;
		}
	}
	
	public Spatial getSpatial(){
		return scene;
	}
}
